const PhoenixError = require('../../models/phoenix-error');
const rule = require('../../models/rules');
const middleware = require('./../middleware');
const analyzeTemplate = require('../../models/analyze-templates');
const { ruleExtraConfig } = require('../../models/rules');

function getRules(req, res, next) {
  (async () => {
    let {
      languages,
      keywords,
    } = req.query;
    const { templateId } = req.query;
    const levelsSet = req.query.levels ? new Set([].concat(req.query.levels).map((item) => parseInt(item, 10))) : undefined;
    languages = languages ? [].concat(languages) : undefined;
    keywords = keywords || undefined;
    let templateInfo = {};
    if (templateId) {
      templateInfo = await analyzeTemplate.getTemplate(templateId);
    }
    const ruleSets = await rule.getRules({
      languages,
      keywords,
    });
    // 组装数据
    ruleSets.forEach((ruleSet) => {
      delete ruleSet._id;
      const levels = ruleSet.rules.reduce((pre, ruleInfo) => {
        rule.formatRulesForUserDefined(ruleInfo, templateInfo.userDefined);
        const {
          level, ruleId, ruleName, ruleCode, originalLevel, orderIndex,
        } = ruleInfo;
        if (levelsSet && !levelsSet.has(level)) {
          return pre;
        }
        const ruleKey = `${ruleSet.ruleSetName}-${ruleCode}`;
        const extraConfig = {};
        const ruleUd = templateInfo.userDefined && templateInfo.userDefined[`${ruleId}`] ? templateInfo.userDefined[`${ruleId}`] : {};
        const udKeySet = new Set(Object.keys(ruleUd));
        Object.keys(ruleExtraConfig).forEach((key) => {
          const {
            default: defaultValue, rules,
          } = ruleExtraConfig[key];
          if (rules.find((item) => item === ruleKey)) {
            extraConfig[key] = udKeySet.has(key) ? ruleUd[key] : defaultValue;
          }
        });
        let levelObj = pre.find((l) => l.level === level);
        if (!levelObj) {
          levelObj = {
            level,
            total: 1,
            rules: [{
              ruleId,
              ruleName,
              ruleCode,
              originalLevel,
              orderIndex,
              ...extraConfig,
            }],
          };
          pre.push(levelObj);
        } else {
          levelObj.total += 1;
          levelObj.rules.push({
            ruleId,
            ruleName,
            ruleCode,
            originalLevel,
            orderIndex,
            ...extraConfig,
          });
        }
        return pre;
      }, []);
      levels.sort((a, b) => (a.level > b.level ? 1 : -1))
        .forEach((level) => level.rules.sort((a, b) => {
          const subLevelOrderFirst = rule.ruleLevelEum[a.originalLevel].subLevelOrder;
          const subLevelOrderSecond = rule.ruleLevelEum[b.originalLevel].subLevelOrder;
          if (subLevelOrderFirst === subLevelOrderSecond) {
            return a.orderIndex > b.orderIndex ? 1 : -1;
          }
          return subLevelOrderFirst > subLevelOrderSecond ? 1 : -1;
        }));
      ruleSet.levels = levels;
      delete ruleSet.rules;
    });
    res.json(ruleSets);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getRule(req, res, next) {
  (async () => {
    const { ruleId } = req.params;
    const exists = await rule.getRuleObject(ruleId);
    if (!exists) {
      throw new PhoenixError('not found', `rule id ${ruleId} not found`);
    }
    const { templateId } = req.query;
    if (templateId) {
      exists.rawLevel = exists.level;
      exists.rawOriginalLevel = exists.originalLevel;
      const template = await analyzeTemplate.getTemplate(templateId);
      rule.formatRulesForUserDefined(exists, template.userDefined);
    }
    exists.createAt = exists.ruleId.generationTime * 1000;
    res.json(exists);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
/**
 * Export model definition object.
 */
module.exports = (app, prefix) => {
  const allRuleURL = `${prefix}/static-analyze/rules.json`;
  const ruleURL = `${prefix}/static-analyze/rules/:ruleId.json`;

  app.get(allRuleURL, middleware.user.requireTokenUnexpired);
  app.get(allRuleURL, middleware.user.requireAvailable);
  app.get(allRuleURL, middleware.user.requireTester);
  app.get(allRuleURL, getRules);

  app.get(ruleURL, middleware.user.requireTokenUnexpired);
  app.get(ruleURL, middleware.user.requireAvailable);
  app.get(ruleURL, middleware.user.requireTester);
  app.get(ruleURL, getRule);
};
